//
//  RSDBTable.m
//  Cellar Tracker
//
//  Created by Johnnie Walker on 09/07/2008.
//  Copyright 2008 Random Sequence. All rights reserved.
//

#import "RSDB.h"
#import "RSDBTable.h"
#import "RSDBResultSet.h"
#import "NSString+Inflection.h"
#import "RSDBQuery.h"

@implementation RSDBTable

@synthesize columns, database, exists, tableName, primaryKeyColumnName;

-(id)initWithTableName:(NSString *)name database:(RSDBDatabase *)db {
	
	[super init];
	
	columns = [[NSMutableDictionary alloc] init];
	[self setDatabase:db];
	[self setTableName:name];
	
	RSDBResultSet *schema;
	if (schema = [db schemaForTable:name]) {
		while([schema next]) {
			NSDictionary *definition = [NSDictionary dictionaryWithObjectsAndKeys:
															[schema numberForColumn:@"cid"], @"cid",
															[schema numberForColumn:@"notnull"], @"notnull",
															[schema numberForColumn:@"pk"], @"pk",
															[schema stringForColumn:@"type"], @"type",
															nil];
			[columns setObject:definition forKey:[schema stringForColumn:@"name"]];
			if ([[definition objectForKey:@"pk"] boolValue]) {
				self.primaryKeyColumnName = [schema stringForColumn:@"name"];
			}
		}
		[schema close];	
		self.exists = YES;
	}
	
	// NSLog(@"%@: %@",self.tableName,columns);
	
	return self;
}

- (void) dealloc
{
	[columns release];
	[super dealloc];
}

- (NSString *)description
{
	return [NSString stringWithFormat:@"%@ %@ (%@)",NSStringFromClass([self class]),[self tableName],[super description]];
}

#pragma mark Queries

- (RSDBQuery *)createQuery {
	
	RSDBQuery *query = [[RSDBQuery alloc] init];
	query.table = self;
	
	return [query autorelease];
}

#pragma mark Record Utilities

- (RSDBRecord *)createRecord
{
	return [[[[self recordClass] alloc] initWithTable:self] autorelease];
}

- (void)empty
{
	NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE 1",self.tableName];
	[[self database] executeUpdate:sql arguments:nil];	
}

#pragma mark Introspection

//- (id) executeQuery:(NSString*)sql, ... {
//    va_list args;
//    va_start(args, sql);
//    
//    id result = [self executeQuery:sql arguments:args];
//    
//    va_end(args);
//    return result;
	
- (Class)recordClass
{
	Class recordClass;
	
	recordClass = NSClassFromString([@"RSDBRecord" stringByAppendingString:[self.tableName classifiedString]]);		
	
	if (nil != recordClass && [recordClass isSubclassOfClass:[RSDBRecord class]]) {
		return recordClass;
	}
	
	return [RSDBRecord class];
}

-(BOOL)hasColumn:(NSString *)columnName
{
	// NSLog(@"%@ (%i)",columnName,(NULL == [columns objectForKey:columnName]));
	return NULL != [columns objectForKey:columnName];
}

#pragma mark Find

- (RSDBRecord *)find:(id)identifier
{
	NSString *sql = [NSString stringWithFormat:@"SELECT * FROM <tablename> WHERE %@ = ? LIMIT 1",self.primaryKeyColumnName];
	//NSLog(@"sql: %@",sql);
	return [self findOneBySQL:sql arguments:[NSArray arrayWithObject:identifier]];
}

- (NSArray *)findAll
{
	NSString *sql = @"SELECT * FROM <tablename> WHERE 1";
	return [self findBySQL:sql arguments:[NSArray array]];	
}

- (NSArray *)findBySQL:(NSString *)sql, ... {
	va_list args;
	va_start(args, sql);
	
	// do this because argumentsFromSQL complains about the <tablename>
	NSString *finalSql = [sql stringByReplacingOccurrencesOfString:@"<tablename>" withString:self.tableName];
	NSArray *results = [self findBySQL:finalSql arguments:[RSDB argumentsFromSQL:finalSql args:args]];
	
	va_end(args);
	
	return results;
}

- (NSArray *)findBySQL:(NSString *)sql arguments:(NSArray *)args
{
	NSString *finalSql = [sql stringByReplacingOccurrencesOfString:@"<tablename>" withString:self.tableName];
	// NSLog(@"finalSql: %@",finalSql);
	// NSLog(@"args: %@",args);	
	RSDBResultSet *resultsSet = [[self database] executeQuery:finalSql arguments:args];
	NSMutableArray *results = [NSMutableArray array];
	
	while ([resultsSet next]) {
		RSDBRecord *record = [[[self recordClass] alloc] initWithTable:self resultsFromSet:resultsSet];
		[results addObject:record];
		[record release];
	}
	
	[resultsSet close];
	return results;
}

- (RSDBRecord *)findOneBySQL:(NSString *)sql, ... {
	va_list args;
	va_start(args, sql);
	
	RSDBResultSet *resultsSet = [[self database] executeQuery:[sql stringByReplacingOccurrencesOfString:@"<tablename>" withString:self.tableName] arguments:[RSDB argumentsFromSQL:sql args:args]];
	//NSLog(@"findBySQL resultsSet columnCount: %i",[resultsSet columnCount]);
	NSMutableArray *results = [NSMutableArray array];
	
	while ([resultsSet next]) {
		RSDBRecord *record = [[[[self recordClass] alloc] initWithTable:self resultsFromSet:resultsSet] autorelease];
		[results addObject:record];
	}
	
	[resultsSet close];
	
	va_end(args);
	
	if ([results count] == 0) {
		return nil;
	}
	
	return [results objectAtIndex:0];
}

- (RSDBRecord *)findOneBySQL:(NSString *)sql arguments:(NSArray *)args
{
	NSArray *results = [self findBySQL:sql arguments:args];
	if ([results count]) {
		return [results objectAtIndex:0];
	}
	
	return nil;
}

@end
